package com.github.shuaidd.rest.runtime;

import com.github.shuaidd.service.runtime.LwfPermissionService;
import org.activiti.app.model.common.ResultListDataRepresentation;
import org.activiti.app.model.runtime.ProcessDefinitionRepresentation;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.editor.language.json.converter.util.CollectionUtils;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.form.api.FormRepositoryService;
import org.activiti.form.model.FormDefinition;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class AbstractProcessDefinitionsResource {

    @Autowired
    protected RepositoryService repositoryService;

    @Autowired
    protected FormRepositoryService formRepositoryService;

    @Autowired
    protected LwfPermissionService permissionService;

    public ResultListDataRepresentation getProcessDefinitions(Boolean latest, String deploymentKey) {

        ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();

        if (deploymentKey != null) {
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentKey(deploymentKey).latest().singleResult();

            if (deployment != null) {
                definitionQuery.deploymentId(deployment.getId());
            } else {
                return new ResultListDataRepresentation(new ArrayList<ProcessDefinitionRepresentation>());
            }

        } else {

            if (latest != null && latest) {
                definitionQuery.latestVersion();
            }
        }

        List<ProcessDefinition> definitions = definitionQuery.list();
        return new ResultListDataRepresentation(convertDefinitionList(definitions));
    }

    protected List<ProcessDefinitionRepresentation> convertDefinitionList(List<ProcessDefinition> definitions) {
        Map<String, Boolean> startFormMap = new HashMap<>();
        List<ProcessDefinitionRepresentation> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(definitions)) {
            for (ProcessDefinition processDefinition : definitions) {
                if (!startFormMap.containsKey(processDefinition.getId())) {
                    BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
                    List<StartEvent> startEvents = bpmnModel.getMainProcess().findFlowElementsOfType(StartEvent.class, false);
                    boolean hasStartForm = false;
                    for (StartEvent startEvent : startEvents) {
                        if (StringUtils.isNotEmpty(startEvent.getFormKey())) {
                            FormDefinition formDefinition = null;
                            try {
                                formDefinition = formRepositoryService.getFormDefinitionByKey(startEvent.getFormKey());
                            } catch (Exception e){
                               //nothing  to do
                            }

                            if (formDefinition != null) {
                                hasStartForm = true;
                                break;
                            }
                        }
                    }

                    startFormMap.put(processDefinition.getId(), hasStartForm);
                }

                ProcessDefinitionRepresentation rep = new ProcessDefinitionRepresentation(processDefinition);
                rep.setHasStartForm(startFormMap.get(processDefinition.getId()));
                result.add(rep);
            }
        }
        return result;
    }
}
